#pragma once

#include "vec.h"

namespace sfc::string {

using namespace str;

struct String : vec::Vec<u8> {
  using Base = vec::Vec<u8>;
  using Base::_cap;
  using Base::_len;
  using Base::_ptr;

  [[sfc_inline]] String() = default;

  [[sfc_inline]] String(Base&& other) : Base{static_cast<Base&&>(other)} {}

  static auto with_capacity(usize cap) -> String {
    return String{Base::with_capacity(cap)};
  }

  static auto from(Str s) -> String {
    auto res = String::with_capacity(s.len());
    res.extend(s.as_bytes());
    return res;
  }

  [[sfc_inline]] operator Str() const {
    return {reinterpret_cast<const char*>(_ptr), _len};
  }

  [[sfc_inline]] auto as_str() const -> Str {
    return *this;
  }

  [[sfc_inline]] auto as_mut_vec() -> Vec<u8>& {
    return *this;
  }

  void push_str(Str s) {
    Base::extend(s.as_bytes());
  }

  void write_str(Str s) {
    Base::extend(s.as_bytes());
  }

  auto find(auto&& pat) const -> Option<usize> {
    return Str{*this}.find(pat);
  }

  auto rfind(auto&& pat) const -> Option<usize> {
    return Str{*this}.rfind(pat);
  }

  auto starts_with(auto&& pat) const -> bool {
    return Str{*this}.starts_with(pat);
  }

  auto ends_with(auto&& pat) const -> bool {
    return Str{*this}.ends_with(pat);
  }

  auto contains(auto&& pat) const -> bool {
    return Str{*this}.contains(pat);
  }
};

auto format(const auto&... args) {
  auto res = String{};
  fmt::write(res, args...);
  return res;
}

}  // namespace sfc::string
